/**
 *    Copyright (C) 2008, 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_API_COLLECTIONS_MANAGER_HPP
#define	_CUBEFS_CORE_API_COLLECTIONS_MANAGER_HPP

#include <cubefs/api/models/manager.hpp>
#include <cubefs/core/api/metadata/page.hpp>
#include <cubefs/core/api/models/logs.hpp>

#define CUBEFS_SOURCE "cubefs/core/api/models/manager.hpp:" CUBEFS_AT

#define CUBEFS_THROW_NOT_SUPPORTED {throw CubefsException(CUBEFS_SOURCE, "Method is not supported for this Container type");}

namespace cubefs    {
namespace api       {

template <typename Interface>
class ManagerImplT: public TypedImplT<Interface> {
	typedef ManagerImplT<Interface>		Me;
	typedef TypedImplT<Interface>		Base;

public:

	virtual BigInt GetPageCount()       				= 0;
	virtual Page*  CreatePageWrapper()					= 0;
	virtual void GetRootPageId(TypedIDValue* id)		= 0;
	virtual void SetRootPageId(TypedIDValue* id)		= 0;
	virtual void GetPage(Page* page, TypedIDValue* id) 	= 0;
	virtual void RemovePage(TypedIDValue* id) 			= 0;
	virtual void CreateNewPage(int flags, Page* page)   = 0;

    virtual Logger& logger() {
        return logger_;
    }

    virtual Logger* GetLogger() {
        return &logger_;
    }

    static void Init()
    {
        AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), Container::MyType());
        type_ = type;

        type->AddOperation(new BasicOperation<void (Me::*)(TypedIDValue*)>(type, "GetRootPageId", "id", &Me::GetRootPageId));
        type->AddOperation(new BasicOperation<void (Me::*)(TypedIDValue*)>(type, "SetRootPageId", "id", &Me::SetRootPageId));

        type->AddOperation(new BasicOperation<Typed* (Me::*)(), Page* (Me::*)()>(type, Page::MyType(), "CreatePageWrapper", &Me::CreatePageWrapper));
        type->AddOperation(new BasicOperation<void (Me::*)(Page*, TypedIDValue*)>(type, "GetPage", "page", "id", &Me::GetPage));

        type->AddOperation(new BasicOperation<void (Me::*)(TypedIDValue*)>(type, "RemovePage", "id", &Me::RemovePage));
        type->AddOperation(new BasicOperation<void (Me::*)(int, Page*)>(type, "CreateNewPage", "flags", "page", &Me::CreateNewPage));

        type->AddOperation(new BasicOperation<Typed* (Me::*)(), Logger* (Me::*)()>(type, Logger::MyType(), "GetLogger", &Me::GetLogger));
        type->AddOperation(new BasicOperation<BigInt (Me::*)()>(type, "GetPageCount", &Me::GetPageCount));
    }


    virtual Int ContainerType() 										CUBEFS_THROW_NOT_SUPPORTED;
    virtual void SetContainerType(Int container_type) 					CUBEFS_THROW_NOT_SUPPORTED;

    virtual cubefs::api::TreeMap *GetRootMap() 							CUBEFS_THROW_NOT_SUPPORTED;
    virtual Manager* GetManager() 										CUBEFS_THROW_NOT_SUPPORTED;
    virtual void SetManager(Manager* manager) 							CUBEFS_THROW_NOT_SUPPORTED;

    virtual cubefs::api::Model* GetCollection(TypedIDValue* rootId) 	CUBEFS_THROW_NOT_SUPPORTED;
    virtual cubefs::api::Model* GetCollectionByName(BigInt name) 		CUBEFS_THROW_NOT_SUPPORTED;

    virtual cubefs::api::Model* CreateCollection(Int type, BigInt name) CUBEFS_THROW_NOT_SUPPORTED;
    virtual void ReleaseCollection(cubefs::api::Model* collection) 		CUBEFS_THROW_NOT_SUPPORTED;
    virtual void RemoveCollection(cubefs::api::Model* collection) 		CUBEFS_THROW_NOT_SUPPORTED;

    virtual bool Check() 												CUBEFS_THROW_NOT_SUPPORTED;

    virtual void SetPlugin(cubefs::api::Plugin* plugin) 				CUBEFS_THROW_NOT_SUPPORTED;
    virtual cubefs::api::Plugin* GetPlugin() 							CUBEFS_THROW_NOT_SUPPORTED;

    virtual ContainerMetadata* 	GetMetadata() 							CUBEFS_THROW_NOT_SUPPORTED;
    virtual RootMapInterfaceBase* GetRootMapInterface() 				CUBEFS_THROW_NOT_SUPPORTED;


    CUBEFS_DECLARE_REFLECTION;
    
private:
    LoggerImpl logger_;
};

template <typename Interface>
Type* ManagerImplT<Interface>::type_ 		= NULL;
typedef ManagerImplT<Manager>				ManagerImpl;



template <typename Interface>
class InputStreamHandlerImplT: public TypedImplT<Interface> {
	typedef InputStreamHandlerImplT<Interface>	Me;
	typedef TypedImplT<Interface>				Base;
public:

    virtual Int available() = 0;
    virtual void close() = 0;
    virtual Int buffer_size() = 0;
    virtual Int read(void* mem, Int offset, Int length) = 0;

    virtual bool read(void* mem, Int size)
    {
        Int size0 = size;
        while (size > 0) {
            Int r = read(mem, 0, size);
            if (r < 0) {
                if (size != size0) {
                    throw CubefsException(CUBEFS_SOURCE, "End Of File");
                }
                else {
                    return false;
                }
            }
            else {
                size -= r;
            }
        }
        return true;
    }

    static void Init() {
        AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), Typed::MyType());
        type_ = type;
    }

    CUBEFS_DECLARE_REFLECTION;
};

template <typename Interface>
Type* InputStreamHandlerImplT<Interface>::type_			= NULL;
typedef InputStreamHandlerImplT<InputStreamHandler>		InputStreamHandlerImpl;



template <typename Interface>
class OutputStreamHandlerImplT: public TypedImplT<Interface> {
	typedef OutputStreamHandlerImplT<Interface>	Me;
	typedef TypedImplT<Interface>				Base;

public:
    virtual Int buffer_size() = 0;

    virtual void flush() = 0;
    virtual void close() = 0;
    virtual void write(const void* mem, int offset, int lenght) = 0;

    static void Init() {
    	AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), Typed::MyType());
    	type_ = type;
    }

    CUBEFS_DECLARE_REFLECTION;
};

template <typename Interface>
Type* OutputStreamHandlerImplT<Interface>::type_	= NULL;
typedef OutputStreamHandlerImplT<OutputStreamHandler>	OutputStreamHandlerImpl;

CUBEFS_DEFINE_PARAMETER_TYPE(OutputStreamHandler);
CUBEFS_DEFINE_PARAMETER_TYPE(InputStreamHandler);



template <typename Interface>
class StreamManagerImplT: public ManagerImplT<Interface> {
	typedef StreamManagerImplT<Interface>	Me;
	typedef ManagerImplT<Interface>			Base;

public:
    virtual void load(InputStreamHandler *input) = 0;
    virtual void store(OutputStreamHandler *output) = 0;

    static void Init()
    {
    	AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), Manager::MyType());
        type_ = type;

        type->AddOperation(new BasicOperation<void (Me::*)(InputStreamHandler*)>(type, "load", "input", &Me::load));
        type->AddOperation(new BasicOperation<void (Me::*)(OutputStreamHandler*)>(type, "store", "output", &Me::store));
    }

    CUBEFS_DECLARE_REFLECTION;
};

template <typename Interface>
Type* StreamManagerImplT<Interface>::type_		= NULL;
typedef StreamManagerImplT<StreamManager>		StreamManagerImpl;



}
}

#undef CUBEFS_SOURCE
#undef CUBEFS_THROW_NOT_SUPPORTED

#endif	//_CUBEFS_API_COLLECTIONS_ITERATOR_HPP
